#include "CHttpReqLimited.h"
#include "tinyxml.h"
#include "tinystr.h"
#include <wx/msgdlg.h>
#include "Utils.h"


#ifdef RATE_LIMIT_DB
    CQuery CHttpReqLimited::dbQuery_for_rateLimit;
    wxString CHttpReqLimited::lastResetTime(dbQuery_for_rateLimit.getSystemParam("last_reset_time"));
#endif
int CHttpReqLimited::rateUsed = -1;
//int CHttpReqLimited::rateRemaning = 0;
long CHttpReqLimited::resetSec = 0;
wxString CHttpReqLimited::nextResetTime(wxT(""));
#ifndef RATE_LIMIT_DB
    wxString CHttpReqLimited::lastResetTime(wxT(""));
#endif



CHttpReqLimited::CHttpReqLimited (const bool auth, const int retrySec_IN, const int timeOutSec_IN)
:CHttpReq (auth, retrySec_IN, timeOutSec_IN)
{

}

CHttpReqLimited::~CHttpReqLimited ()
{

}




bool CHttpReqLimited::startReqLimited(const wxString& urlStr_IN,
                                                            long count,
                                                            long cursor,
                                                            const wxString& postBuf)
{

    wxString urlStr(urlStr_IN);

    if(count!=0)
    {
        urlStr<<wxString("&count=")<<count;
    }
    if(cursor!=0)
    {
        urlStr<<wxString("&cursor=")<<cursor;
    }

    #ifdef RATE_LIMIT_DEBUG
        wxMessageBox(urlStr);
    #endif

    // -1 indicates that the app is re-opened.
    // Normally , the rateUsed in RAM is expected to be the same as the one in DB
    // So, no need to fetch from DB every time.
    // It's a static var. As long as the app runs , this var is expect to stay valid.
    #ifdef RATE_LIMIT_DB
        if(rateUsed==-1)
        {
            dbQuery_for_rateLimit.getSystemParam("rate_used").ToLong((long *)&rateUsed);
        }
    #endif


    if(! isRateLimited())
    {
        ++rateUsed;
        #ifdef RATE_LIMIT_DEBUG
            wxMessageBox(wxString("rateUsed : ")<<rateUsed);
        #endif
        #ifdef RATE_LIMIT_DEBUG_LOG
            logger.logOut(wxString("rateUsed : ")<<rateUsed);
        #endif

        #if (defined(RATE_LIMIT_DB) && defined(USE_RATE_LIMIT))
            dbQuery_for_rateLimit.setSystemParam("rate_used",wxString("")<<rateUsed);
        #endif
        return startReq(urlStr,postBuf);
    }else
    {
        return false;
    }
}

bool CHttpReqLimited::currentRateReq()
{
    DOM* xmlDoc = NULL;
    Node* root = NULL;
    Node* currentChild = NULL;
    wxString textValue(wxT(""));

    using std::runtime_error;

    try
    {
        //Warning !  If any of the False reached , the ptrs may not be reset to 0. Then , dangling ptrs
        CHttpReq rateReq(true);
        if(rateReq.startReq(wxT(SINA_RATE_LIMIT_API)))
        {
            xmlDoc = new DOM();
            xmlDoc->Parse(rateReq.reqResult.ToUTF8());
            root = xmlDoc->RootElement();
            if(root != NULL)    //root == <users>
            {
                /*************** Write reset seconds into resetSec *****************/
                currentChild = root->FirstChild("reset-time-in-seconds");
                if(currentChild!=NULL)
                {
                    textValue = textValue.FromUTF8(currentChild->ToElement()->GetText());
                    if(! textValue.ToLong(&resetSec))
                    {
                        throw runtime_error("Unable to get numerical reset seconds");
                    }
                }else
                {
                    throw runtime_error("rate limit XML has no reset seconds node");
                }//End of if(currentChild)

                /**************** Write reset time into resetTime *******************/
                currentChild = root->FirstChild("reset-time");
                if(currentChild!=NULL)
                {
                    nextResetTime = textValue.FromUTF8(currentChild->ToElement()->GetText());
                }else
                {
                    throw runtime_error("rate limit XML has no reset time node");
                }//End of if(currentChild)

                //up to now, both reset sec & time sync successfully:
                delete xmlDoc;
                xmlDoc = NULL;
                root = NULL;
                currentChild = NULL;

                return true;

            }else
            {
                throw runtime_error("rate limit XML doc is empty");
            }//End of if(root)

        }else
        {
            throw runtime_error((const char*) (wxString("Unable to request rate limit , Error : ")<<rateReq.httpErrCode).c_str());
        }//End of startReq()
    }catch(runtime_error& e)
    {
        #ifdef RATE_LIMIT_DEBUG
            wxMessageBox(e.what());
        #endif

        #ifdef RATE_LIMIT_LOG
            LOGMAN.logError(e.what());
        #endif

        delete xmlDoc;
        xmlDoc = NULL;
        root = NULL;
        currentChild = NULL;

        return false;
    }//End of try

    //It shouldn't be run to here, just in case
    return false;
}//End of currentRateReq()



bool CHttpReqLimited::isRateLimited()
{
    if(rateUsed < SINA_RATE_LIMIT_NUM && lastResetTime != wxT(""))
    {
        return false;
    }else
    {
        if(currentRateReq())
        {
            if(nextResetTime == lastResetTime)
            {
                #ifdef RATE_LIMIT_DEBUG
                    wxMessageBox(wxString("lastResetTime : ")<<lastResetTime<<"     "<<wxString("nextResetTime : ")<<nextResetTime);
                #endif
                #ifdef RATE_LIMIT_DEBUG_LOG
                    logger.logOut(wxString("lastResetTime : ")<<lastResetTime<<"     "<<wxString("nextResetTime : ")<<nextResetTime);
                #endif
                wxMessageBox(wxString(wxT(RATE_LIMIT_ERROR))<<wxString(wxT("，需要等待大约"))<<resetSec/60<<wxString(wxT("分钟")));
                return true;
            }
            else
            {
                #ifdef RATE_LIMIT_DEBUG
                    wxMessageBox(wxString("lastResetTime : ")<<" ?  "<<wxString("nextResetTime : ")<<nextResetTime);
                #endif
                #ifdef RATE_LIMIT_DEBUG_LOG
                    logger.logOut(wxString("lastResetTime : ")<<" ?  "<<wxString("nextResetTime : ")<<nextResetTime);
                #endif
                lastResetTime = nextResetTime;
                rateUsed = 0;
                #ifdef RATE_LIMIT_DB
                    dbQuery_for_rateLimit.setSystemParam("last_reset_time",lastResetTime);
                    dbQuery_for_rateLimit.setSystemParam("rate_used",wxString("")<<rateUsed);
                #endif
                return false;
            }
        }else
        {
            //Unable to synchronize rate limit
            //wxMessageBox(_T(SYNC_RATE_LIMIT_ERROR));
            return true;
        }//End of currentRateReq()

    }//End of if(rateUsed<SINA_RATE_LIMIT)
}//End of isRateLimited()
